﻿using System;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;

namespace Xenta.Utils
{
    /// <summary>
    /// Represents the system helper.
    /// </summary>
    public static class SystemHelper
    {
        #region Methods

        /// <summary>
        /// Gets file system rights for the directory.
        /// </summary>
        /// <param name="path">The directory path.</param>
        /// <param name="identity">The windows indentity.</param>
        /// <returns>The file sytem rights.</returns>
        public static FileSystemRights GetDirectoryRights(string path, WindowsIdentity identity)
        {
            if(identity == null)
                throw new ArgumentNullException("identity");

            FileSystemRights result = 0;
            try
            {
                var ruleCollection = Directory.GetAccessControl(path)
                    .GetAccessRules(true, true, typeof(SecurityIdentifier))
                    .Cast<FileSystemAccessRule>();

                foreach(var reference in identity.Groups)
                {
                    foreach(var rule in ruleCollection)
                    {
                        if(!reference.Equals(rule.IdentityReference))
                            continue;
                        if(rule.AccessControlType != AccessControlType.Allow) 
                            continue;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Delete))
                            result |= FileSystemRights.Delete;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Modify))
                            result |= FileSystemRights.Modify;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Read))
                            result |= FileSystemRights.Read;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Write))
                            result |= FileSystemRights.Write;
                    }
                }
                foreach(var rule in ruleCollection)
                {
                    if(!identity.User.Equals(rule.IdentityReference))
                        continue;
                    if(rule.AccessControlType != AccessControlType.Deny) 
                        continue;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Delete))
                        result |= FileSystemRights.Delete;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Modify))
                        result |= FileSystemRights.Modify;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Read))
                        result |= FileSystemRights.Read;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Write))
                        result |= FileSystemRights.Write;
                }
            }
            catch
            {
            }
            return result;
        }

        /// <summary>
        /// Gets file system rights for the file.
        /// </summary>
        /// <param name="path">The file path.</param>
        /// <param name="identity">The windows indentity.</param>
        /// <returns>The file sytem rights.</returns>
        public static FileSystemRights GetFileRights(string path, WindowsIdentity identity)
        {
            if(identity == null)
                throw new ArgumentNullException("identity");

            FileSystemRights result = 0;
            try
            {
                var ruleCollection = File.GetAccessControl(path)
                    .GetAccessRules(true, true, typeof(SecurityIdentifier))
                    .Cast<FileSystemAccessRule>();

                foreach(var reference in identity.Groups)
                {
                    foreach(var rule in ruleCollection)
                    {
                        if(!reference.Equals(rule.IdentityReference))
                            continue;
                        if(rule.AccessControlType != AccessControlType.Allow)
                            continue;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Delete))
                            result |= FileSystemRights.Delete;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Modify))
                            result |= FileSystemRights.Modify;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Read))
                            result |= FileSystemRights.Read;
                        if(rule.FileSystemRights.HasFlag(FileSystemRights.Write))
                            result |= FileSystemRights.Write;
                    }
                }
                foreach(var rule in ruleCollection)
                {
                    if(!identity.User.Equals(rule.IdentityReference))
                        continue;
                    if(rule.AccessControlType != AccessControlType.Deny) 
                        continue;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Delete))
                        result |= FileSystemRights.Delete;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Modify))
                        result |= FileSystemRights.Modify;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Read))
                        result |= FileSystemRights.Read;
                    if(rule.FileSystemRights.HasFlag(FileSystemRights.Write))
                        result |= FileSystemRights.Write;
                }
            }
            catch
            {
            }
            return result;
        }

        #endregion
    }
}
